package com.party.web.biz.asynexport;

import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import com.party.common.constant.Constant;
import com.party.common.redis.StringJedis;
import com.party.common.utils.DateUtils;
import com.party.common.utils.FileUtils;
import com.party.common.utils.LangUtils;
import com.party.common.utils.StringUtils;
import com.party.core.model.YesNoStatus;
import com.party.core.model.activity.Activity;
import com.party.core.model.crowdfund.EventGradation;
import com.party.core.model.crowdfund.ProjectWithAuthor;
import com.party.core.model.crowdfund.SupportWithMember;
import com.party.core.service.activity.IActivityService;
import com.party.core.service.crowdfund.IEventGradationService;
import com.party.core.service.picCloud.CosCloudBizService;
import com.party.core.utils.MyBeanUtils;
import com.party.file.cos.dto.UploadResult;
import com.party.file.cos.meta.InsertOnly;
import com.party.web.biz.crowdfund.ProjectBizService;
import com.party.web.biz.crowdfund.SupportBizService;
import com.party.web.biz.crowdfundMultiple.ProjectMultipleBizService;
import com.party.web.redisPubSub.publish.RedisMsgPublish;
import com.party.web.redisPubSub.subscribe.SubScribeMessage;
import com.party.web.utils.RealmUtils;
import com.party.web.web.dto.output.crowdfund.ProjectForActivityMultiOutput;
import com.party.web.web.dto.output.crowdfund.ProjectForActivityOutput;
import com.sun.istack.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 众筹批量导入
 * Created by wei.li
 *
 * @date 2017/7/19 0019
 * @time 14:52
 */

@SuppressWarnings("all")
@Service
@Component(value = "projectAsynExportService")
public class ProjectAsynExportService implements IAsynExportService {

    Logger logger = LoggerFactory.getLogger(getClass());
    private Integer target = 0;
    private String targetId = null;
    @Autowired
    private ProjectBizService projectBizService;
    @Autowired
    private SupportBizService supportBizService;
    @Autowired
    private AsynExportBizService asynExportBizService;
    @Autowired
    private IActivityService activityService;
    @Autowired
    private StringJedis stringJedis;
    private String uploadPath = Constant.UPLOAD_ZIP;
    @Autowired
    private CosCloudBizService cosCloudBizService;
    @Autowired
    private IEventGradationService eventGradationService;
    @Autowired
    private ProjectMultipleBizService projectMultipleBizService;
    @Autowired
    private RedisMsgPublish redisMsgPublish;

    /**
     * 异步导出回调业务
     *
     * @param result 是否成功(true/false)
     */
    @Override
    public synchronized void callBack(Boolean result, String fileName1, boolean isEnd) {
        if (isEnd) {

            String targetUrl = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + targetId + "_" + fileName1;
            String fileName = fileName1 + targetId + ".zip";
            String cloudFilePath = String.format(uploadPath, fileName);
            try {
                InputStream inputStream = FileUtils.zipFiles(targetUrl, "*");

                long start = System.currentTimeMillis();
                UploadResult uploadResult = cosCloudBizService.uploadFile(inputStream, cloudFilePath, InsertOnly.OVER_WRITE);
                long end = System.currentTimeMillis();
                logger.info("上传文件用时：{}(ms)", (end - start));
                logger.info("上传成功路径：{}", uploadResult.getSourceUrl());
                String sourceUrl = uploadResult.getSourceUrl();
                Map<String,Object> map = Maps.newHashMap();
                map.put("sourceUrl", sourceUrl);
                map.put("uploadTime", DateUtils.formatDate(new Date(), DateUtils.DATETIME_PATTERN));

                //设置24小时过期
                stringJedis.setValue(Constant.PRE_ZIP_URL + fileName1 + targetId, JSONObject.toJSONString(map));
                FileUtils.deleteDirectory(asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + targetId + "_" + fileName1);
            } catch (Exception e) {
                logger.error("众筹上传压缩文件异常", e);
            }
        }
    }


    /**
     * 导出
     *
     * @param id 目标编号
     * @param sessionId
     */
    @Override
    public <T> void export(String id, T t, String sessionId) {
        Activity activity = activityService.get(id);
        try {
            String path = id + "_crowdfund";
            targetId = id;
            ProjectWithAuthor projectWithAuthor = (ProjectWithAuthor) t;
            projectWithAuthor.setTargetId(id);
            projectWithAuthor.setPayType(0);
            if (null != projectWithAuthor.getIsSuccess() && 0 == projectWithAuthor.getIsSuccess()) { // 众筹中
                projectWithAuthor.setIsSuccess(10);
            }
            List<ProjectForActivityOutput> projectForActivityOutputList = projectBizService.projectForActivityList(projectWithAuthor, null);
            target = projectForActivityOutputList.size() + 1;

            IAsynExportService asynExportService = new ProjectAsynExportService();

            ExecutorService threadPool = Executors.newFixedThreadPool(30);

            for (ProjectForActivityOutput output : projectForActivityOutputList) {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        long start = System.currentTimeMillis();
                        List<SupportWithMember> list = supportBizService.listForProjectId(output.getId(), null, null, null);
                        long end = System.currentTimeMillis();
                        logger.info("{}的支持者查询用时：{}(ms)", output.getAuthorName(), (end - start));
                        String newFilePath = Constant.replaceDirSpecial(output.getAuthorName()).replaceAll(" ", "");
                        String realPath = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/" + newFilePath
                                + DateUtils.formatNowToYMDHMS() + new Random().nextInt(99999) + "/";
                        String fileName = DateUtils.formatNowToYMDHMS() + ".xlsx";
                        asynExportBizService.export(fileName, SupportWithMember.class, list, realPath, asynExportService, null, false);
                    }
                });
            }
            threadPool.shutdown();

            while(true){
                if(threadPool.isTerminated()){
                    logger.info("所有的子线程都结束了！");
                    break;
                }
            }

            asynExportBizService.export2(Constant.replaceDirSpecial(activity.getTitle()) + "的众筹.xlsx", ProjectForActivityOutput.class,
                    projectForActivityOutputList, asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/", this, "crowdfund", true);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹人员导出成功了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        } catch (Exception e) {
            logger.error("导出异常", e);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹人员导出异常了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        }
    }


    /**
     * 导出直接众筹
     *
     * @param id
     * @param sessionId
     */
    @Override
    public <T> void exportDPData(String id, T t, String sessionId) {
        Activity activity = activityService.get(id);
        try {
            String path = id + "_zczjfk_crowdfund";
            targetId = id;
            ProjectWithAuthor projectWithAuthor = (ProjectWithAuthor) t;
            projectWithAuthor.setTargetId(id);
            projectWithAuthor.setPayType(1);
            if (null != projectWithAuthor.getIsSuccess() && 0 == projectWithAuthor.getIsSuccess()) { // 众筹中
                projectWithAuthor.setIsSuccess(10);
            }
            List<ProjectForActivityOutput> projectForActivityOutputList = projectBizService.projectForActivityList(projectWithAuthor, null);
            target = projectForActivityOutputList.size() + 1;

            IAsynExportService asynExportService = new ProjectAsynExportService();

            ExecutorService threadPool = Executors.newFixedThreadPool(30);

            for (ProjectForActivityOutput output : projectForActivityOutputList) {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        List<SupportWithMember> list = supportBizService.listForProjectId(output.getId(), null, null, null);
                        String newFilePath = Constant.replaceDirSpecial(output.getAuthorName()).replaceAll(" ", "");
                        String realPath = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/" + newFilePath
                                + DateUtils.formatNowToYMDHMS() + new Random().nextInt(99999) + "/";
                        String fileName = DateUtils.formatNowToYMDHMS() + ".xlsx";
                        asynExportBizService.export(fileName, SupportWithMember.class, list, realPath, asynExportService, null, false);
                    }
                });
            }

            threadPool.shutdown();

            while(true){
                if(threadPool.isTerminated()){
                    logger.info("所有的子线程都结束了！");
                    break;
                }
            }

            asynExportBizService.export2(Constant.replaceDirSpecial(activity.getTitle()) + "的直接众筹.xlsx", ProjectForActivityOutput.class,
                    projectForActivityOutputList, asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/", this, "zczjfk_crowdfund", true);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹直接付款人员导出成功了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        } catch (Exception e) {
            logger.error("导出异常", e);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹直接付款人员导出异常了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        }

    }


    @Override
    public <T> void exportTransferData(String id, T t, String sessionId) {
        Activity activity = activityService.get(id);
        try {
            String path = id + "_zczr_crowdfund";
            targetId = id;
            ProjectWithAuthor projectWithAuthor = (ProjectWithAuthor) t;
            projectWithAuthor.setTargetId(id);
            projectWithAuthor.setTransferP(true);
            if (null != projectWithAuthor.getIsSuccess() && 0 == projectWithAuthor.getIsSuccess()) { // 众筹中
                projectWithAuthor.setIsSuccess(10);
            }
            List<ProjectForActivityOutput> projectForActivityOutputList = projectBizService.projectTransferForActivityList(projectWithAuthor, null, RealmUtils.getCurrentUser().getId());
            target = projectForActivityOutputList.size() + 1;

            IAsynExportService asynExportService = new ProjectAsynExportService();

            ExecutorService threadPool = Executors.newFixedThreadPool(30);

            for (ProjectForActivityOutput output : projectForActivityOutputList) {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        List<SupportWithMember> list = supportBizService.listForProjectId(output.getId(), null, null, null);
                        String newFilePath = Constant.replaceDirSpecial(output.getAuthorName()).replaceAll(" ", "");
                        String realPath = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/" + newFilePath
                                + DateUtils.formatNowToYMDHMS() + new Random().nextInt(99999) + "/";
                        String fileName = DateUtils.formatNowToYMDHMS() + ".xlsx";
                        asynExportBizService.export(fileName, SupportWithMember.class, list, realPath, asynExportService, null, false);
                    }
                });
            }

            threadPool.shutdown();

            while(true){
                if(threadPool.isTerminated()){
                    logger.info("所有的子线程都结束了！");
                    break;
                }
            }
            asynExportBizService.export2(Constant.replaceDirSpecial(activity.getTitle()) + "的转入众筹.xlsx", ProjectForActivityOutput.class,
                    projectForActivityOutputList, asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/", this, "zczr_crowdfund", true);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹转入人员导出成功了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        } catch (Exception e) {
            logger.error("导出异常", e);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"众筹转入人员导出异常了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        }
    }

    @Override
    public synchronized void callBack(Boolean result, String fileName1, boolean isEnd, String cloudName) {
        if (isEnd) {
            String targetUrl = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + targetId + "_" + fileName1;
            String fileName = cloudName.substring(10, 15) + targetId + ".zip";
            String cloudFilePath = String.format(uploadPath, fileName);
            try {
                InputStream inputStream = FileUtils.zipFiles(targetUrl, "*");
                UploadResult uploadResult = cosCloudBizService.uploadFile(inputStream, cloudFilePath, InsertOnly.OVER_WRITE);
                logger.info("上传成功路径：{}", uploadResult.getSourceUrl());
                String sourceUrl = uploadResult.getSourceUrl();
                Map<String,Object> map = Maps.newHashMap();
                map.put("sourceUrl", sourceUrl);
                map.put("uploadTime", DateUtils.formatDate(new Date(), DateUtils.DATETIME_PATTERN));

                //设置24小时过期
                stringJedis.setValue(Constant.PRE_ZIP_URL + cloudName.substring(10, 15) + targetId, JSONObject.toJSONString(map));
                FileUtils.deleteDirectory(asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + targetId + "_" + fileName1);
            } catch (Exception e) {
                logger.error("众筹上传压缩文件异常", e);
            }
        }
    }

    @Override
    public <T> void exportMultipleProject(String id, T t, String sessionId) {
        Activity activity = activityService.get(id);
        try {
            String path = id + "_multi_crowdfund";
            targetId = id;
            ProjectWithAuthor projectWithAuthor = (ProjectWithAuthor) t;
            projectWithAuthor.setTargetId(id);
            projectWithAuthor.setPayType(0);
            projectWithAuthor.setDistribution(true);

            String[] array = {"一", "二", "三", "四", "五"};

            EventGradation eventGradation = eventGradationService.get(projectWithAuthor.getCurrentGradation());
            String tt = array[eventGradation.getGradation() - 1];

            List<ProjectForActivityOutput> projectForActivityOutputList = projectMultipleBizService.projectQueryCommon(projectWithAuthor, projectWithAuthor.getCurrentGradation(), null);
            List<ProjectForActivityMultiOutput> multiOutputs = LangUtils.transform(projectForActivityOutputList, new Function<ProjectForActivityOutput, ProjectForActivityMultiOutput>() {
                @Nullable
                @Override
                public ProjectForActivityMultiOutput apply(@Nullable ProjectForActivityOutput input) {
                    ProjectForActivityMultiOutput output = new ProjectForActivityMultiOutput();
                    try {
                        MyBeanUtils.copyBeanNotNull2Bean(input, output);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (null != input.getCompetitionStatus()) {
                        output.setCompStatus(YesNoStatus.getValue(input.getCompetitionStatus()));
                    }
                    return output;
                }
            });
            target = projectForActivityOutputList.size() + 1;

            IAsynExportService asynExportService = new ProjectAsynExportService();

            ExecutorService threadPool = Executors.newFixedThreadPool(30);

            for (ProjectForActivityOutput output : projectForActivityOutputList) {
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        List<SupportWithMember> list = supportBizService.listForProjectId(output.getId(), null, null, null);
                        String newFilePath = "无名";
                        if (StringUtils.isNotEmpty(output.getAuthorName())) {
                            newFilePath = Constant.replaceDirSpecial(output.getAuthorName()).replaceAll(" ", "");
                        }
                        String realPath = asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/" + newFilePath
                                + DateUtils.formatNowToYMDHMS() + new Random().nextInt(99999) + "/";
                        String fileName = DateUtils.formatNowToYMDHMS() + ".xlsx";
                        asynExportBizService.export(fileName, SupportWithMember.class, list, realPath, asynExportService, null, false);
                    }
                });
            }
            threadPool.shutdown();

            while (true) {
                if (threadPool.isTerminated()) {
                    logger.info("所有的子线程都结束了！");
                    break;
                }
            }
            asynExportBizService.export(Constant.replaceDirSpecial(activity.getTitle()) + "第" + tt + "场活动的众筹.xlsx", ProjectForActivityMultiOutput.class,
                    multiOutputs, asynExportBizService.getBaseDir() + Constant.BATCH + Constant.EXCEL_URL + path + "/",
                    this, "multi_crowdfund", true, projectWithAuthor.getCurrentGradation());
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"多场众筹人员导出成功了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        } catch (Exception e) {
            logger.error("导出异常", e);
            Map<String, String> json = Maps.newHashMap();
            json.put("memberId", RealmUtils.getCurrentUser().getId());
            json.put("sessionId", sessionId);
            json.put("message", "\"" + activity.getTitle() + "\"多场众筹人员导出异常了");
            String param = JSONUtils.toJSONString(json);
            redisMsgPublish.publish(SubScribeMessage.CROWDFUND_EXPORT_CHANNEL_NAME, param);
        }
    }
}
